<script lang="ts" setup>
import type { EditInfrenceBasicInfo } from "@/common/apis/train/type"
import { createTaskApi, getTaskInfoApi, updateTaskApi } from "@/common/apis/train"
import { DEFAULT_DEDUCT_BASIC, INIT_DATE_COLLECTION } from "@/common/apis/train/type"
import { FormTypeEnum } from "@/common/constants/other-keys"
import { closeRoute } from "@@/composables/useCloseRouteListener"
import { Check } from "@element-plus/icons-vue"
import { cloneDeep, isEmpty } from "lodash-es"
import { onActivated, onMounted, ref, nextTick, onBeforeUnmount } from "vue"
import { useRouter } from "vue-router"
import { AgentSetting, BasicInfo, SimlSetting, TrainSetting, DataCollectEdit, SituationInfo } from "./components"

defineOptions({
  name: "DeductCreate"
})

const router = useRouter()
const route = useRoute()
const activeIndex = ref(0)
const showView = ref(true)
const showEdit = ref(false)
const currentId = ref<string>(route.query.id as string)
// 常量和类型定义
let TOTAL_STEPS = 0
const STEP_TITLES = ["基本信息配置", "智能体配置", "仿真配置", "推演配置", "数据采集", "态势信息配置"] as const
// 响应式状态
const currentComponentRef = ref()
const ruleForm = reactive<EditInfrenceBasicInfo>(cloneDeep(DEFAULT_DEDUCT_BASIC))

// 引用内容区域元素
const stepsContentRef = ref<HTMLElement | null>(null)
// 存储每个步骤的内容元素位置信息
const stepPositions = ref<Array<{ id: string, top: number, bottom: number }>>([])


// 监听滚动事件，更新活动索引
let isScrollingProgrammatically = false; // 添加标志，指示是否正在进行编程式滚动

function handleHeaderClick(index: number) {
  activeIndex.value = index
  // 设置编程式滚动标志
  isScrollingProgrammatically = true
  // 滚动到对应内容
  scrollToStep(index)
  // 延迟重置标志，给滚动操作足够的时间完成
  setTimeout(() => {
    isScrollingProgrammatically = false
  }, 1000) // 设置足够长的时间，覆盖滚动完成的时间
}

function scrollToStep(index: number) {
  const targetId = `step-content-${index}`
  const targetElement = document.getElementById(targetId)

  if (targetElement && stepsContentRef.value) {
    // 获取容器的可见高度
    const containerHeight = stepsContentRef.value.clientHeight
    // 获取目标元素位置信息
    const targetRect = targetElement.getBoundingClientRect()
    // 获取容器的位置信息
    const containerRect = stepsContentRef.value.getBoundingClientRect()
    // 计算元素相对于容器的顶部偏移
    const relativeTop = targetElement.offsetTop
    // 计算滚动位置，确保元素在可视区域
    const scrollPosition = relativeTop - 20 // 添加一点顶部间距

    // 使用滚动方法
    stepsContentRef.value.scrollTo({
      top: scrollPosition - 100,
      behavior: 'smooth'
    })
  }
}

// 计算所有步骤区域的位置信息
function calculateStepPositions() {
  stepPositions.value = []
  for (let i = 0; i < STEP_TITLES.length; i++) {
    const element = document.getElementById(`step-content-${i}`)
    if (element) {
      const rect = element.getBoundingClientRect()
      const containerRect = stepsContentRef.value?.getBoundingClientRect()
      const offsetTop = element.offsetTop
      const height = rect.height

      stepPositions.value.push({
        id: `step-content-${i}`,
        top: offsetTop,
        bottom: offsetTop + height
      })
    }
  }
}

// 监听滚动事件，更新活动索引
function handleScroll() {
  // 如果是编程式滚动触发的，则不更新activeIndex
  if (isScrollingProgrammatically || !stepsContentRef.value || stepPositions.value.length === 0) return

  const scrollTop = stepsContentRef.value.scrollTop
  const scrollOffset = 150 // 考虑到滚动偏移量
  const adjustedScrollTop = scrollTop + scrollOffset

  // 找到当前视图中的步骤
  for (let i = 0; i < stepPositions.value.length; i++) {
    const { top, bottom } = stepPositions.value[i]

    // 判断当前滚动位置是否在某个步骤区域内
    if (adjustedScrollTop >= top && adjustedScrollTop < bottom) {
      if (activeIndex.value !== i) {
        activeIndex.value = i
      }
      break
    }

    // 如果已经滚动到最后，则激活最后一个步骤
    if (i === stepPositions.value.length - 1 && adjustedScrollTop >= bottom) {
      activeIndex.value = i
    }
  }
  if (scrollTop > 700) {
    showView.value = false
    showEdit.value = true
  } else {
    showView.value = true
    showEdit.value = false
  }
}
async function saveCurrentStep(): Promise<void> {
  dataCollectEditRef.value.updateData()
  // 保存基本信息
  // 创建一个深拷贝，并处理可能的循环引用
  const formToSave = JSON.parse(JSON.stringify(
    ruleForm,
    (key, value) => {
      // 跳过parent属性，这是造成循环引用的主要原因
      if (key === 'parent') {
        return undefined;
      }
      return value;
    }
  ));
  if (isEmpty(ruleForm.task_id)) {
    // 创建
    const { data } = await createTaskApi(formToSave)
    ruleForm.task_id = data.task_id
  } else {
    // 更新
    await updateTaskApi(formToSave)
  }
}

// 保存
const basicInfoRef = ref<any>(null)
const simlSettingRef = ref<any>(null)
const agentSettingRef = ref<any>(null)
const trainSettingRef = ref<any>(null)
const dataCollectEditRef = ref<any>(null)
const situationInfoRef = ref<any>(null)

// 验证所有表单
async function validateAllForms(): Promise<boolean> {
  try {
    // 创建一个包含所有组件ref的数组
    const componentRefs = [
      basicInfoRef,
      agentSettingRef,
      simlSettingRef,
      trainSettingRef,
      dataCollectEditRef,
      situationInfoRef
    ]

    // 存储验证结果的数组
    const validationResults: { index: number, isValid: boolean, error?: any }[] = []
    const invalidSteps: number[] = []

    // 收集所有验证结果 - 无论成功或失败都继续验证其他组件
    for (let i = 0; i < componentRefs.length; i++) {
      const ref = componentRefs[i]
      if (ref && ref.value && typeof ref.value.validate === 'function') {
        try {
          // 尝试验证每个组件
          const isValid = await ref.value.validate()
          validationResults.push({ index: i, isValid })

          if (!isValid) {
            invalidSteps.push(i)
          }
        } catch (error) {
          validationResults.push({ index: i, isValid: false, error })
          invalidSteps.push(i)
        }
      }
    }

    // 如果有任何验证未通过的组件，显示错误并滚动到第一个错误的组件
    if (invalidSteps.length > 0) {
      // 滚动到第一个错误的步骤
      const firstInvalidStep = invalidSteps[0]
      handleHeaderClick(firstInvalidStep)
      return false
    }

    // 所有组件验证通过
    return true
  } catch (error) {
    return false
  }
}

// 在合适的位置添加这个函数，手动触发所有表单的验证
async function validateAllFormsManually() {
  // 手动触发验证过程
  if (basicInfoRef.value && basicInfoRef.value.$el) {
    const forms = basicInfoRef.value.$el.querySelectorAll('form');
    forms.forEach((form: any) => {
      // 提交表单以触发验证
      const event = new Event('submit', { cancelable: true });
      form.dispatchEvent(event);
    });
  }

  // 对其他表单组件执行同样的操作
  const formComponents = [
    trainSettingRef.value,
    agentSettingRef.value,
    dataCollectEditRef.value,
    situationInfoRef.value
  ];

  formComponents.forEach(component => {
    if (component && component.$el) {
      const forms = component.$el.querySelectorAll('form');
      forms.forEach((form: any) => {
        const event = new Event('submit', { cancelable: true });
        form.dispatchEvent(event);
      });
    }
  });
}

async function handleExitAndSave() {
  // 手动触发所有表单验证
  await validateAllFormsManually();

  // 然后验证所有表单
  const isValid = await validateAllForms();

  if (!isValid) {
    return // 如果验证不通过，直接返回
  }

  try {
    // 验证通过后保存
    await saveCurrentStep()
    ElMessage.success("保存成功")
    closeRoute()
    router.replace({ name: "MyProjectDeductIndex" })
  } catch (error) {
    console.error('保存过程中出错:', error)
    ElMessage.error('保存失败，请稍后再试')
  }
}

// 辅助方法
async function validateCurrentStep(): Promise<boolean> {
  if (!currentComponentRef.value?.validate) return true
  return await currentComponentRef.value.validate()
}

// 类型转换函数，将服务器返回的数据转换为EditInfrenceBasicInfo
function convertToInferenceData(data: any): EditInfrenceBasicInfo {
  // 创建一个新对象，只复制EditInfrenceBasicInfo需要的字段
  const result: EditInfrenceBasicInfo = {
    task_id: data.task_id,
    task_mode: data.task_mode || "Inference",
    task_name: data.task_name,
    task_tag: data.task_tag || [],
    task_describe: data.task_describe,
    project_id: data.project_id,
    sim_config: data.sim_config || {
      engine_id: undefined,
      scn_id: undefined,
      max_step: 1,
      speed_up_ratio: 1
    },
    agent_config: data.agent_config || {
      red: [],
      blue: []
    },
    inference_config: data.inference_config || {
      task_config: {
        resources: {
          cpu_num: 1,
          distributed_enable: false,
          gpu_num: 1,
          worker_num: 1
        }
      },
      episode_config: {
        max_episode: 10
      }
    },

    data_collections: data.data_collections || INIT_DATE_COLLECTION,
    // 添加态势信息配置
    situation_config: data.situation_config || {
      is_enable: false,
      params: {
        ip: '',
        port: '',
        username: '',
        password: '',
        rmpAddress: ''
      }
    }
  };

  return result;
}

function getTaskInfo() {
  if (!currentId.value) return
  getTaskInfoApi(currentId.value).then((res) => {
    // 获取原始数据
    const rawData = res.data;

    // 处理智能体配置的selectId
    if (rawData && 'agent_config' in rawData && rawData.agent_config) {
      // 确保不复制循环引用
      if (Array.isArray(rawData.agent_config.red)) {
        rawData.agent_config.red = rawData.agent_config.red.map((item: any) => {
          // 创建一个新对象，不包含可能导致循环引用的属性
          return {
            ...item,
            selectId: new Date().getTime(),
            // 移除可能的循环引用属性
            parent: undefined
          };
        });
      }

      if (Array.isArray(rawData.agent_config.blue)) {
        rawData.agent_config.blue = rawData.agent_config.blue.map((item: any) => {
          return {
            ...item,
            selectId: new Date().getTime(),
            // 移除可能的循环引用属性
            parent: undefined
          };
        });
      }
    }

    // 转换数据类型，使用JSON序列化/反序列化来去除循环引用
    const taskData = convertToInferenceData(
      JSON.parse(
        JSON.stringify(rawData, (key, value) => {
          // 跳过parent属性
          if (key === 'parent') {
            return undefined;
          }
          return value;
        })
      )
    );

    // 应用到表单
    Object.assign(ruleForm, cloneDeep(taskData));

    // 在数据加载完成后计算步骤位置
    nextTick(() => {
      calculateStepPositions();
    });
  });
}
// 保存
onMounted(() => {
  getTaskInfo()

  // 在组件挂载后，添加滚动事件监听器
  nextTick(() => {
    calculateStepPositions()
    if (stepsContentRef.value) {
      stepsContentRef.value.addEventListener('scroll', handleScroll)
    }

    // 添加窗口大小变化监听器
    window.addEventListener('resize', calculateStepPositions)
  })
})

onActivated(() => {
  if (currentId.value && currentId.value !== route.query.id) {
    TOTAL_STEPS = 6
    currentId.value = route.query.id as string
    getTaskInfo()
  }
})

// 在组件卸载前移除事件监听器
onBeforeUnmount(() => {
  if (stepsContentRef.value) {
    stepsContentRef.value.removeEventListener('scroll', handleScroll)
  }

  // 移除窗口大小变化监听器
  window.removeEventListener('resize', calculateStepPositions)
})
</script>

<template>
  <div class="app-container">
    <div class="header-steps">
      <ul>
        <li v-for="(step, index) in STEP_TITLES" :key="step" :class="{ active: activeIndex === index }"
          @click="handleHeaderClick(index)">
          <SvgIcon name="info-step" class="svg-icon primary" />
          <span style="display: inline-block;margin-left: 10px;">{{ step }}</span>
        </li>
      </ul>
    </div>
    <div class="steps-content" ref="stepsContentRef">
      <BasicInfo :dialog-type="FormTypeEnum.CREATE" v-model:rule-form="ruleForm" ref="basicInfoRef"
        class="steps-wrapper" :id="`step-content-0`" />
      <AgentSetting :dialog-type="FormTypeEnum.CREATE" v-model:rule-form="ruleForm" ref="currentComponentRef"
        class="steps-wrapper" :id="`step-content-1`" />
      <SimlSetting :dialog-type="FormTypeEnum.CREATE" v-model:rule-form="ruleForm" ref="simlSettingRef"
        class="steps-wrapper" :id="`step-content-2`" />
      <TrainSetting :dialog-type="FormTypeEnum.CREATE" v-model:rule-form="ruleForm" ref="currentComponentRef"
        class="steps-wrapper" :id="`step-content-3`" style="padding-right: 100px; overflow-x: hidden;" />
      <DataCollectEdit :dialog-type="FormTypeEnum.CREATE" v-model:rule-form="ruleForm" ref="dataCollectEditRef"
        class="steps-wrapper" :id="`step-content-4`" />
      <SituationInfo :dialog-type="FormTypeEnum.CREATE" v-model:rule-form="ruleForm" ref="situationInfoRef"
        class="steps-wrapper" :id="`step-content-5`" />
    </div>
    <div class="pager-wrapper">
      <el-button type="primary" v-throttle="() => handleExitAndSave()" :icon="Check" native-type="submit">
        保存并退出
      </el-button>
    </div>
  </div>
</template>

<style lang="scss" scoped>
@import "@@/assets/styles/mixins.scss";

.app-container {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  overflow: hidden;

  .header-steps {
    width: 150px;
    height: calc(100vh - 140px);
    // background: var(--el-bg-color);
    border-radius: 4px;
    padding: 24px 0;
    display: flex;
    justify-content: center;
    padding-right: 0px;

    /* 横向居中 */
    ul {
      width: 150px;
      margin: 0;
      padding: 0;

      li {
        list-style: none;
        text-align: left;
        cursor: pointer;
        padding: 22px 20px;
        margin-bottom: 16px;
        /* 👈 控制间距关键 */
        color: rgba(255, 255, 255, 0.6);

        :hover {
          color: rgba(255, 255, 255, 1); // 不变色变亮
        }

        &.active {
          >span {
            color: #FFF;
          }
        }
      }
    }
  }

  .steps-content {
    padding-left: 24px;
    width: calc(100vw - 240px);
    height: calc(100vh - 184px);
    overflow-y: scroll;
    @extend %scrollbar;
  }

  .pager-wrapper {
    margin-top: 20px;
    display: flex;
    gap: 12px;
    position: fixed;
    bottom: 0px;
    right: -30px;
    justify-content: center;
    left: 50%;
    transform: translate(-45%, -0%);
  }
}

.el-step.is-active {
  cursor: pointer;
}

:deep(.el-step__head.is-success),
:deep(.el-step__title.is-success) {
  border-color: var(--el-color-primary) !important;
  color: var(--el-color-primary) !important;
}

// 过渡动画
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

.fixed-button {
  position: fixed;
  right: 30px;
  bottom: 20vh;
  z-index: 9999;
  cursor: pointer;
}
</style>
